home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
os2
/
fst03f.zip
/
do_fat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-16
|
43KB
|
1,404 lines
/* do_fat.c -- FAT-specific code for fst
Copyright (c) 1995-1996 by Eberhard Mattes
This file is part of fst.
fst is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
fst is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fst; see the file COPYING. If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* TODO: Don't assume a sector size of 512 bytes. */
#include <os2.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#include "fst.h"
#include "crc.h"
#include "diskio.h"
#include "fat.h"
struct vfat
{
char flag;
char unprintable;
BYTE total;
BYTE index;
BYTE checksum;
int start;
BYTE name[256+1];
};
static ULONG first_sector;
static ULONG total_sectors;
static ULONG total_clusters;
static ULONG sectors_per_cluster;
static ULONG bytes_per_cluster;
static ULONG sectors_per_fat;
static ULONG number_of_fats;
static ULONG root_entries;
static ULONG root_sectors;
static ULONG data_sector;
static ULONG what_cluster;
static USHORT **fats;
static USHORT *fat;
static BYTE *usage_vector; /* One byte per cluster, indicating usage */
static const path_chain **path_vector; /* One path name chain per sector */
static BYTE find_comp[256]; /* Current component of `find_path' */
static char ea_ok;
static ULONG ea_data_start;
static ULONG ea_data_size;
static ULONG ea_data_clusters;
static USHORT ea_table1[240]; /* First table from `EA DATA. SF' */
static USHORT *ea_table2; /* Second table from `EA DATA. SF' */
static ULONG ea_table2_entries;
static BYTE *ea_usage; /* One byte per cluster of `EA DATA. SF' */
#define CLUSTER_TO_SECTOR(c) (((c) - 2) * sectors_per_cluster + data_sector)
#define SECTOR_TO_CLUSTER(s) (((s) - data_sector) / sectors_per_cluster + 2)
/* Rotate right a byte by one bit. */
static INLINE BYTE rorb1 (BYTE b)
{
return (b & 1) ? (b >> 1) | 0x80 : b >> 1;
}
/* Compare two file names pointed to by P1 and P2. */
static int compare_fname (const BYTE *p1, const BYTE *p2)
{
for (;;)
{
if (*p1 == 0 && *p2 == 0)
return 0;
if (*p2 == 0)
return 1;
if (*p1 == 0)
return -1;
if (cur_case_map[*p1] > cur_case_map[*p2])
return 1;
if (cur_case_map[*p1] < cur_case_map[*p2])
return -1;
++p1; ++p2;
}
}
/* Return a pointer to a string containing a formatted range of
cluster numbers. Note that the pointer points to static memory; do
not use format_cluster_range() more than once in one expression! */
static const char *format_cluster_range (ULONG start, ULONG count)
{
static char buf[60];
if (count == 1)
sprintf (buf, "cluster %lu", start);
else
sprintf (buf, "%lu clusters %lu-%lu", count, start, start + count - 1);
return buf;
}
/* Return a pointer to a string containing a file time as string.
Note that the pointer points to static memory; do not use
format_time() more than once in one expression! */
static const char *format_time (unsigned t)
{
static char buf[20];
sprintf (buf, "%.2d:%.2d:%.2d",
(t >> 11) & 31, (t >> 5) & 63, (t & 31) << 1);
return buf;
}
/* Return a pointer to a string containing a file date as string.
Note that the pointer points to static memory; do not use
format_date() more than once in one expression! */
static const char *format_date (unsigned d)
{
static char buf[20];
sprintf (buf, "%d-%.2d-%.2d",
((d >> 9) & 127) + 1980, (d >> 5) & 15, d & 31);
return buf;
}
/* Return the number of days in month M of year Y. */
static int days (int y, int m)
{
static int month_len[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (m < 1 || m > 12)
return 0;
else if (m != 2)
return month_len[m-1];
else
return y % 4 != 0 ? 28 : y % 100 != 0 ? 29 : y % 400 != 0 ? 28 : 29;
}
/* Types of clusters. */
#define USE_EMPTY 0
#define USE_FILE 1
#define USE_DIR 2
/* Return a pointer to a string containing a description of a cluster
type. */
static const char *cluster_usage (BYTE what)
{
switch (what)
{
case USE_EMPTY:
return "empty";
case USE_DIR:
return "directory";
case USE_FILE:
return "file";
default:
return "INTERNAL_ERROR";
}
}
/* Use cluster CLUSTER for WHAT. PATH points to a string naming the
object for which the cluster is used. PATH points to the path name
chain for the file or directory. Return FALSE if a cycle has been
detected. */
static int use_cluster (ULONG cluster, BYTE what, const path_chain *path)
{
BYTE old;
if (cluster >= total_clusters)
abort ();
old = usage_vector[cluster];
if (old != USE_EMPTY)
{
warning (1, "Cluster %lu usage conflict: %s vs. %s",
cluster, cluster_usage (usage_vector[cluster]),
cluster_usage (what));
if (path_vector != NULL && path_vector[cluster] != NULL)
warning_cont ("File 1: \"%s\"",
format_path_chain (path_vector[cluster], NULL));
if (path != NULL)
warning_cont ("File 2: \"%s\"",
format_path_chain (path, NULL));
return !(path != NULL && path == path_vector[cluster]);
}
else
{
usage_vector[cluster] = what;
if (path_vector != NULL)
path_vector[cluster] = path;
return TRUE;
}
}
static void dirent_warning (int level, const char *fmt, ULONG secno,
const path_chain *path,
const BYTE *name, ...) ATTR_PRINTF (2, 6);
static USHORT *read_fat16 (DISKIO *d, ULONG secno)
{
USHORT *fat;
ULONG sectors, clusters, i;
clusters = total_clusters;
sectors = DIVIDE_UP (clusters * 2, 512);
if (sectors != sectors_per_fat)
warning (1, "Incorrect FAT size: %lu vs. %lu", sectors, sectors_per_fat);
fat = xmalloc (sectors * 512);
read_sec (d, fat, secno, sectors, TRUE);
for (i = 0; i < clusters; ++i)
fat[i] = USHORT_FROM_FS (fat[i]);
return fat;
}
static USHORT *read_fat12 (DISKIO *d, ULONG secno)
{
USHORT *fat;
ULONG clusters, sectors, i, s, t;
USHORT c1, c2;
BYTE *raw;
clusters = total_clusters;
sectors = DIVIDE_UP (clusters * 3, 512*2);
if (sectors != sectors_per_fat)
warning (1, "Incorrect FAT size: %lu vs. %lu", sectors, sectors_per_fat);
raw = xmalloc (sectors * 512 + 2);
read_sec (d, raw, secno, sectors, TRUE);
fat = xmalloc (clusters * 2 + 1);
s = 0;
for (i = 0; i < clusters; i += 2)
{
t = raw[s+0] | (raw[s+1] << 8) | (raw[s+2] << 16);
c1 = t & 0xfff;
if (c1 >= 0xff7)
c1 |= 0xf000;
c2 = (t >> 12) & 0xfff;
if (c2 >= 0xff7)
c2 |= 0xf000;
fat[i+0] = c1;
fat[i+1] = c2;
s += 3;
}
free (raw);
return fat;
}
static USHORT *read_fat (DISKIO *d, ULONG secno, ULONG fatno)
{
if (a_what)
{
if (!what_cluster_flag && IN_RANGE (what_sector, secno, sectors_per_fat))
info ("Sector #%lu: Fat %lu (+%lu)\n", what_sector, fatno + 1,
what_sector - secno);
}
if (total_clusters - 2 > 4085)
return read_fat16 (d, secno);
else
return read_fat12 (d, secno);
}
static void do_fats (DISKIO *d)
{
ULONG secno, i, j, k, free, bad;
fats = xmalloc (number_of_fats * sizeof (*fats));
secno = first_sector;
for (i = 0; i < number_of_fats; ++i)
{
if (a_info)
info ("FAT %lu: